/// /////////////////////////////////////////////
// 单元名 : unitBlockMsgClient
// 作者 : Hawk
// 单元描述 : 阻塞式套接字Msg扩展类
// 日期 : 2023-09-15
/// /////////////////////////////////////////////

{$IFDEF FPC}
{$H+}
{$MODE DELPHI}
{$ENDIF}
unit unitBlockMsgClient;

interface

uses
{$IFnDEF FPC}
  Windows,
{$ELSE}
{$ENDIF}
  unitCommonDataStruct, unitMsgObj, unitBlockSocket, unitIOCPDataObj;

{$R-}
{$Q-}

type
  TOnRecvMsg = procedure(Sender: TObject; msg: TMsg) of object;

  TBlockMsgClient = class(TTCPClient)
  private
    FOnRecvMsg: TOnRecvMsg;
    function ReadMsgFromPack(dp: TIOCPDataCollecter): TMsg;
  protected
    function IsPackComplete(var PackSize: Longword): Boolean; override;
    procedure DoPackRecved; override;
  public
    procedure SendMsg(msg: TMsg); overload;
    procedure SendMsg(const Target, Source: TID_OBJ; msgID: Longword; const tblID: TID_OBJ; param: TSerialObj = nil;
      data: Longword = 0); overload;

    property OnRecvMsg: TOnRecvMsg read FOnRecvMsg write FOnRecvMsg;
  end;

implementation

uses unitMisc, unitNetCommon, unitObjPool, unitMsgDef, unitClassIDDef{$IFDEF DEBUG}, unitUniqueDataCommon,
  unitSvrMngCommon{$ENDIF};

{ TBlockMsgClient }

function TBlockMsgClient.IsPackComplete(var PackSize: Longword): Boolean;
begin
  PackSize := Longword(-1);
  RecvBuf.GetBuf(@PackSize, SizeOf(PackSize));
  PackSize := PackSize + SizeOf(TMSG_HEADER);
  Result := PackSize <= RecvBuf.DataCapacity;
end;

function TBlockMsgClient.ReadMsgFromPack(dp: TIOCPDataCollecter): TMsg;
var
  Flag, ClsID: Longword;
begin
  Result := nil;
  Flag := dp.ReadLSB;
  if Flag = OBJFLAG_CLASSID_LSB then
  begin
    ClsID := dp.ReadLSB;
    if ClsID = CLASSID_MSG then
    begin
      Result := ObjPool.GetObj(TMsg, Self);
      Result.ReadFromPack(dp);
    end;
  end;
end;

procedure TBlockMsgClient.SendMsg(const Target, Source: TID_OBJ; msgID: Longword; const tblID: TID_OBJ;
  param: TSerialObj; data: Longword);
var
  m: TMsg;
begin
  m := TMsg(ObjPool.GetObj(TMsg, Self));
  m.ObjID := tblID;
  m.TargetObjID := Target;
  m.SourceObjID := Source;
  m.msgID := msgID;
  m.data := data;
  m.AddObj(param);
  SendMsg(m);
end;

procedure TBlockMsgClient.DoPackRecved;
var
  Tag: Longword;
  m: TMsg;
begin
  if RecvBuf.DataCapacity >= SizeOf(Tag) * 2 then
  begin
    RecvBuf.ReadBuf(Tag, SizeOf(Tag));
    RecvBuf.ReadBuf(Tag, SizeOf(Tag));
    case Tag of
      NETMSGID_SENDMESSAGE:
        begin
          m := ReadMsgFromPack(RecvBuf);
          if m <> nil then
          begin
{$IFDEF DEBUG}
            if (m.msgID = MESID_UNIQUEDATA_RESP_GETOBJ) and (m.ObjID = ID_HOSTPARAMTABLE) then
              DbgPrint('Recv HostParam from %s', [m.SourceObjID.ToString]);
{$ENDIF}
            if Assigned(FOnRecvMsg) then
              FOnRecvMsg(Self, m)
            else
              ObjPool.ReturnObj(m, Self);
          end
          else
            BreakConn;
        end;
    end;
  end;
end;

procedure TBlockMsgClient.SendMsg(msg: TMsg);
var
  dp, dp1: TIOCPDataCollecter;
  hdr: TMSG_HEADER;
begin
  if msg <> nil then
  begin
    dp1 := TIOCPDataCollecter(ObjPool.GetObj(TIOCPDataCollecter, Self));
    msg.WriteToPack(dp1);
    dp := TIOCPDataCollecter(ObjPool.GetObj(TIOCPDataCollecter, Self));
    hdr.Len := dp1.DataCapacity;
    hdr.ID := NETMSGID_SENDMESSAGE;
    dp.WriteBuf(hdr, SizeOf(hdr));
    while dp1.Count > 0 do
      dp.AddData(dp1.data[0]);
    SendData(dp);
    ObjPool.ReturnObj(msg, Self);
    ObjPool.ReturnObj(dp1, Self);
  end;
end;

end.
